using System;
using System.Collections.Generic;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Runtime.Serialization;
using Microsoft.Phone.Shell;

namespace Columbus
{
    public class TransientStore : ITransientStore
    {
        private const string KnownTypesPattern = "KnownTypes.{0}";

        public void Save<T>(T obj, string key, params Type[] knownTypes)
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (var stream = new IsolatedStorageFileStream(key, System.IO.FileMode.Create, store))
                {
                    var serializer = new DataContractSerializer(typeof(T), knownTypes);
                    serializer.WriteObject(stream, obj);
                }
            }

            var knowTypesKey = String.Format(KnownTypesPattern, key);
            var knownTypeNames = knownTypes.Select(t => t.AssemblyQualifiedName).ToArray();
            var state = PhoneApplicationService.Current.State;
            if (state.ContainsKey(knowTypesKey))
                state[knowTypesKey] = knownTypeNames;
            else
                state.Add(knowTypesKey, knownTypeNames);
        }

        public T Load<T>(string key, params Type[] knownTypes)
        {
            var knowTypesKey = String.Format(KnownTypesPattern, key);
            var allKnownTypes = new List<Type>(knownTypes);

            var state = PhoneApplicationService.Current.State;
            if (state.ContainsKey(knowTypesKey))
            {
                allKnownTypes.AddRange(((string[]) state[knowTypesKey]).Select(Type.GetType).ToArray());
            }

            var deserialized = default(T);
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (var stream = new IsolatedStorageFileStream(key, System.IO.FileMode.OpenOrCreate, store))
                {
                    if (stream.Length > 0)
                    {
                        var serializer = new DataContractSerializer(typeof(T), allKnownTypes.Distinct());
                        deserialized = (T)serializer.ReadObject(stream);
                    }
                }
            }
            return deserialized;
        }

        public void Remove(string keyPattern)
        {
            using (var store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                foreach (var file in store.GetFileNames(keyPattern))
                {
                    store.DeleteFile(file);
                }
            }
        }
    }
}